package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleClient;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class AuditServiceImpl implements IAuditService {

    @Autowired
    GreenTextScan textScan;

    @Autowired
    GreenImageScan imageScan;

    @Autowired
    IWmNewsService newsService;

    @Autowired
    MinIOService minIOService;

    @Autowired
    ArticleClient articleClient;

    @Autowired
    IWmUserService userService;

    @Autowired
    WmChannelService channelService;

    @Autowired
    IWmSensitiveService sensitiveService;

    @Autowired
    RedissonClient redissonClient;

    /**
     * 文章审核
     * @param wmNews
     */
    @Override
    @Async
    public void aduit(WmNews wmNews) {
        System.out.println(Thread.currentThread().getName() + "开启审核");
        //判断文章的状态
        if (wmNews.getStatus() == 4 || wmNews.getStatus() == 8) {
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                sendDelayMsg(wmNews);
            } else {
                publishArticle(wmNews);
            }
            return;
        }
        if (wmNews.getStatus() == 1) {
            //提取自媒体文章中的文本内容和图片
            Map<String,Object> contentMap = getTextAndImageFromContent(wmNews.getContent());
            //提取文本内容
            String text = (String) contentMap.get("text");
            //提取图片内容
            List<String> images = (List<String>) contentMap.get("image");
            //加上封面图片
            List<ImageDto> coverImages = JSON.parseArray(wmNews.getImages(), ImageDto.class);
            for (ImageDto coverImage : coverImages) {
                if (coverImage != null && !StringUtils.isEmpty(coverImage.getUrl())) {
                    if (!images.contains(coverImage.getUrl())) {
                        images.add(coverImage.getUrl());
                    }
                }
            }
            //先进行自管理敏感词的审核
            boolean wordResult = checkWord(text,wmNews);
            if (!wordResult) return;
            //调用阿里云文本审核,添加阿里云工具包的扫描，注入服务类
            boolean textResult = checkText(text,wmNews);
            //文本审核通过后，调用阿里云图片审核
            if (!textResult) return;
            boolean imageResult = checkImage(images,wmNews);
            if (!imageResult) return;
            //图片审核通过，发送自媒体文章到APP库
            //审核通过后，判断发布时间是否大于系统当前时间，如果发布时间大于当前系统时间，修改文章状态为8
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                wmNews.setStatus(8);
                sendDelayMsg(wmNews);
                newsService.updateById(wmNews);
            } else {
                publishArticle(wmNews);
            }
        }
    }

    //发送延迟消息
    private void sendDelayMsg(WmNews wmNews) {
        //创建阻塞队列
        RQueue<String> queue = redissonClient.getBlockingDeque("article-publish");
        //创建延迟队列
        RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
        //使用延迟队列发送延迟消息
        long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();  //时间
        delayedQueue.offer(JSON.toJSONString(wmNews),time, TimeUnit.MILLISECONDS);
    }

    //自管理敏感词审核
    private boolean checkWord(String text, WmNews wmNews) {
        boolean result = false;
        //获取标题+标签+内容
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        //判断是否已经存在敏感词数据，初始化敏感词
        if (SensitiveWordUtil.dictionaryMap.size() == 0) {
             //从数据库查询敏感词
            LambdaQueryWrapper<WmSensitive> qw = new LambdaQueryWrapper<>();
            //select sensitives form wm_sensitive
            qw.select(WmSensitive::getSensitives);
            List<String> words = sensitiveService.listObjs(qw, x -> x.toString());
            //如果不存在，初始化map
            SensitiveWordUtil.initMap(words);
        }
        //调用工具类判断
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() == 0) {
            result = true;
        } else {
            //修改自媒体文章状态为2，并且记录失败原因
            wmNews.setStatus(2);
            Set<String> keySet = map.keySet(); //获得键
            String label = String.join(",", keySet); //将集合装变成字符串
            wmNews.setReason("自管理敏感词审核失败：" + label);
            newsService.updateById(wmNews);
        }
        return result;
    }

    //发布文章到APP库
    private void publishArticle(WmNews wmNews) {
        //远程调用文章微服务保存文章
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);
        dto.setId(null);
        //从自媒体用户表中查询文章作者id
        WmUser wmUser = userService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());
        dto.setAuthorName(wmUser.getName());
        //查询频道信息
        WmChannel wmChannel = channelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);
        List<ImageDto> coverImages = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        List<String> images = new ArrayList<>();
        for (ImageDto coverImage : coverImages) {
            if (coverImage != null && !StringUtils.isEmpty(coverImage.getUrl())) {
                if (!images.contains(coverImage.getUrl())) {
                    images.add(coverImage.getUrl());
                }
            }
        }
        //将集合转换成逗号分割的字符串
        String join = String.join(",", images);
        dto.setImages(join);
        ResponseResult<Long> longResponseResult = articleClient.saveArticle(dto);
        //判断结果
        if (longResponseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long articleId = longResponseResult.getData();
            if (articleId != null) {
                //将文章id写回到自媒体文章表中
                wmNews.setArticleId(articleId);
                wmNews.setStatus(9);
                newsService.updateById(wmNews);
            }
        }
    }

    //阿里云图片审核
    private boolean checkImage(List<String> images, WmNews wmNews) {
        //没有图片直接通过
        if (images.size() == 0) {
            return true;
        }
        boolean result = false;
        //定义需要审核的图片字节数组集合
        List<byte[]> imageList = new ArrayList<>();
        try {
            //如果minIO是由公网的话，可以直接传URL地址给阿里云审核
            //目前我们的minIO是部署在内网，所以需要先下载图片，然后上传到阿里云审核
            //遍历图片集合
            for (String image : images) {
                //下载图片
                InputStream inputStream = minIOService.download(image);
                //将输入流转化为字节数组
                byte[] bytes = IOUtils.toByteArray(inputStream);
                imageList.add(bytes);
            }
            Map map = imageScan.imageScan(imageList);
            String suggestion = (String) map.get("suggestion");
            //判断结果
            switch (suggestion) {
                case "pass":
                    result = true;
                    break;
                case "block":
                    //修改自媒体文章状态为2，并且记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云图片审核失败：" + label);
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    //修改自媒体状态为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //阿里云文本审核
    private boolean checkText(String text, WmNews wmNews) {
        boolean result = false;
        //审核内容包含标题+标签+内容中的文本
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        try {
            Map map = textScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            //判断结果
            switch (suggestion) {
                case "pass":
                    result = true;
                    break;
                case "block":
                    //修改自媒体文章状态为2，并且记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核失败：" + label);
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    //修改自媒体状态为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //提取自媒体文章中的文本内容和图片
    private Map<String, Object> getTextAndImageFromContent(String content) {
        Map<String, Object> map = new HashMap<>();
        //定义文本内容
        StringBuilder sb = new StringBuilder();
        //定义图片的URL地址集合
        List<String> images = new ArrayList<>();
        //讲content转换成对象集合
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        for (ContentDto contentDto : contentDtos) {
            if (contentDto.getType().equals("text")) {
                //文字内容
                sb.append(contentDto.getValue());
            } else {
                //图片
                images.add(contentDto.getValue());
            }
        }
        map.put("text",sb.toString());
        map.put("image",images);
        return map;
    }
}
